package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;

import com.livestocksolutions.Bovine;
import com.livestocksolutions.Business;
import com.livestocksolutions.Deacquisition;
import com.livestocksolutions.Feed;
import com.livestocksolutions.FeedHistory;
import com.livestocksolutions.Group;
import com.livestocksolutions.Join;
import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.Medicine;
import com.livestocksolutions.MedicineHistory;
import com.livestocksolutions.Mob;
import com.livestocksolutions.Observation;
import com.livestocksolutions.Owner;
import com.livestocksolutions.Paddock;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Table;
import com.livestocksolutions.util.UsableItemList;

import javax.swing.SwingConstants;
import javax.swing.DefaultComboBoxModel;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
 * Show list and details relating to a Group or Mob stored in the system to the user.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 19 March 2013
 */
public class GroupPanel extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;
	
	/**
	 * The initial view for this tab.
	 * Shows all Groups and Mobs that are in the system.
	 */
	public static final int MOB_GROUP_LIST = 0;
	/**
	 * To create a new Group.
	 */
	public static final int VIEW_NEW_GROUP=1;
	/**
	 * To create a new Mob.
	 */
	public static final int VIEW_NEW_MOB=2;
	/**
	 * The default View when selecting a Group or Mob to show in detail.
	 */
	public static final int VIEW=3;
	/**
	 * Showing the details of a Group.
	 */
	public static final int GROUP=4;
	/**
	 * Showing the details of a Mob.
	 */
	public static final int MOB=5;
	/**
	 * The default View when selecting a Group or Mob to show in detail.
	 * Shows Details of the selected Mob/Group and also any Observations for that Mob or Group
	 */
	public static final int VIEW_OBSERVATION = 6;
	/**
	 * Shows Details of the selected Mob/Group and also any Members for that Mob or Group
	 */
	public static final int VIEW_MEMBER = 7;
	/**
	 * Shows Details of the selected Mob and also any Joinings for that Mob
	 */
	public static final int MOB_JOINING = 8;
	
	/**
	 * The current view.
	 * 
	 * @see #MOB_GROUP_LIST
	 * @see #VIEW_NEW_GROUP
	 * @see #VIEW_NEW_MOB
	 * @see #VIEW
	 * @see #GROUP
	 * @see #MOB
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_MEMBER
	 * @see #MOB_JOINING
	 */
	protected int viewing = -1;
	
	/**
	 * The ID of the Group or Mob we are Viewing
	 */
	protected long groupViewID = -1;
	/**
	 * The Type of Group or Mob that is being viewed.
	 */
	protected int viewType = GROUP;
	
	/**
	 * Determine if the editable details of a Group or Mob is editable.
	 */
	protected boolean edit = false;
	
	protected JTextField txtName = new JTextField("-1");
	protected JComboBox listLocation = new JComboBox();
	protected JTextArea txtDescription = new JTextArea("-1");
	
	/**
	 * The list of Cattle to add to the current Group or Mob
	 */
	private ArrayList<Bovine> bovineAddList = new ArrayList<Bovine>();
	
	protected Paddock[] paddocks;
	protected String[] paddockNames;

	protected final JPanel panel = new JPanel();
	/**
	 * The Panel where the innerlist for a particular item will rest.
	 */
	protected JTabbedPane jisp = new JTabbedPane();
	protected final JPanel observationsListPanel = new JPanel();
	protected final JPanel membersListPanel = new JPanel();
	protected final JPanel joiningListPanel = new JPanel();
	
	/**
	 * Sort the list by Name tag.
	 */
	protected static final int LIST_ORDER_NAME = 0;
	/**
	 * Sort the list by Mob Location tag.
	 * Only available for use with Mob Objects.
	 */
	protected static final int LIST_ORDER_LOCATION = 1;
	/**
	 * Sort the list by the number of members.
	 */
	protected static final int LIST_ORDER_COUNT	= 2;
	/**
	 * Sort the observation list by Creation Date.
	 */
	protected static final int LIST_ORDER_DATE = 0;
	/**
	 * Sort the observation list by using the Priority.
	 */
	protected static final int LIST_ORDER_PRIORITY 	= 1;
	
	/**
	 * Sort the member list by Visual ID tag.
	 */
	protected static final int LIST_ORDER_VISUAL = 0;
	/**
	 * Sort the member list by using NLIS ID.
	 */
	protected static final int LIST_ORDER_NLIS 	= 1;
	/**
	 * Sort the member list by using RF ID.
	 */
	protected static final int LIST_ORDER_RF 	= 2;
	/**
	 * Sort the member list by DOB.
	 */
	protected static final int LIST_ORDER_DOB 	= 3;
	/**
	 * Sort the member list by active status.
	 */
	protected static final int LIST_ORDER_ACTIVE	= 4;
	/**
	 * Sort the joining list by using bull entry date.
	 */
	protected static final int LIST_ORDER_ENTRY 	= 0;
	/**
	 * Sort the joining list by using bull exit date.
	 */
	protected static final int LIST_ORDER_EXIT 	= 1;
	/**
	 * Sort the joining list by using bull visual ID.
	 */
	protected static final int LIST_ORDER_BULL 	= 2;
	/**
	 * Sort the joining list by using number of cows in the join.
	 */
	protected static final int LIST_ORDER_COW_COUNT	= 3;

	/**
	 * The current list order method.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_COUNT
	 */
	protected int orderMobListBy = LIST_ORDER_NAME, orderGroupListBy = LIST_ORDER_NAME;
	/**
	 * The items Observation list order method.
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_PRIORITY
	 */
	protected int orderObservationListBy = LIST_ORDER_DATE;
	/**
	 * The current member list order method.
	 * @see #LIST_ORDER_VISUAL
	 * @see #LIST_ORDER_NLIS
	 * @see #LIST_ORDER_RF
	 * @see #LIST_ORDER_DOB
	 * @see #LIST_ORDER_ACTIVE
	 */
	protected int orderMemberListBy = LIST_ORDER_VISUAL;
	
	/**
	 * The current joining list order method.
	 * @see #LIST_ORDER_ENTRY
	 * @see #LIST_ORDER_EXIT
	 * @see #LIST_ORDER_BULL
	 * @see #LIST_ORDER_COW_COUNT
	 */
	protected int orderJoiningListBy = LIST_ORDER_VISUAL;
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderMobHighToLow = 1, orderGroupHighToLow = 1, orderObservationHighToLow = 1, orderMemberHighToLow = 1, orderJoiningHighToLow = 1;
	
	/**
	 * Constructor
	 */
	public GroupPanel(){
		JScrollPane jsp = new JScrollPane();
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());
		add(jsp);
		
		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);
	}
	
	/**
	 * Show the contents of the current page.
	 */
	@Override
	public void displayPanel(){
		int panel = viewing;
		if(viewing==MOB_GROUP_LIST) {
			viewing=-1;
			panel = MOB_GROUP_LIST;
		}
		displayPanel(panel);
	}
	
	/**
	 * @see #MOB_GROUP_LIST
	 * @see #VIEW_NEW_GROUP
	 * @see #VIEW_NEW_MOB
	 * @see #VIEW
	 * @see #GROUP
	 * @see #MOB
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_MEMBER
	 * @see #MOB_JOINING
	 */
	@Override
	public void displayPanel(int panel){
		switch(panel){
			case MOB_GROUP_LIST:
				if(viewing!=MOB_GROUP_LIST){
					createMainPanel();
				}
				break;

			case VIEW_NEW_MOB:
				if(viewing!=VIEW_NEW_MOB){
					createMobPanel(-1L);
				}
				break;
			case VIEW_NEW_GROUP:
				if(viewing!=VIEW_NEW_GROUP){
					createGroupPanel(-1);
				}
				break;
				
			case VIEW:
			case GROUP:
			case MOB:
			case VIEW_OBSERVATION:	
			case VIEW_MEMBER:
			case MOB_JOINING:
				if(viewType==MOB){
					createMobPanel(groupViewID);
				}else{
					createGroupPanel(groupViewID);
				}
				break;
			default :
				createMainPanel();
		}
	}
	
	private void createMainPanel(){
		viewing = MOB_GROUP_LIST;
		groupViewID = 0;
		panel.setLayout(new BorderLayout(0, 0));
		
		final int NAME 		= 0;
		final int DESCRIPTION	= 1;
		final int GROUP_COUNT	= 2;
		
		final Table groupPanel = new Table("Group List",false,
			"Name","Description","No. Members");
		groupPanel.setEmptyMessage("There are no Groups to show.");

		final int MOB_LOCATION		= 2;
		final int MOB_COUNT		= 3;
		
		final Table mobPanel = new Table("Mob List",false,
			"Name","Description","Location","No. Members");
		mobPanel.setEmptyMessage("There are no Groups to show.");
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				mobPanel.setHeaderClickable(DESCRIPTION, false);
				mobPanel.setHeaderOrderedBy(orderMobListBy==LIST_ORDER_NAME?NAME:orderMobListBy==LIST_ORDER_LOCATION?MOB_LOCATION:orderMobListBy==LIST_ORDER_COUNT?MOB_COUNT:NAME, orderMobHighToLow==1);
				mobPanel.addHeaderMouseListener(NAME, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMobHighToLow = orderMobHighToLow*(orderMobListBy==LIST_ORDER_NAME?-1:1);
						orderMobListBy = LIST_ORDER_NAME;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				mobPanel.addHeaderMouseListener(MOB_LOCATION, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMobHighToLow = orderMobHighToLow*(orderMobListBy==LIST_ORDER_LOCATION?-1:1);
						orderMobListBy = LIST_ORDER_LOCATION;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				mobPanel.addHeaderMouseListener(MOB_COUNT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMobHighToLow = orderMobHighToLow*(orderMobListBy==LIST_ORDER_COUNT?-1:1);
						orderMobListBy = LIST_ORDER_COUNT;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Mob[] mList = LivestockSolutions.getOnlyMobs();
				Arrays.sort(mList, 
					orderMobListBy==LIST_ORDER_NAME?
						orderMobHighToLow==1?Comparators.mobComparatorName:Collections.reverseOrder(Comparators.mobComparatorName)
					:orderMobListBy==LIST_ORDER_LOCATION?
						orderMobHighToLow==1?Comparators.mobComparatorLocation:Collections.reverseOrder(Comparators.mobComparatorLocation)
					:orderMobHighToLow==1?Comparators.mobComparatorCount:Collections.reverseOrder(Comparators.mobComparatorCount));

				for(int x=0; x<mList.length; x++){
					String location=mList[x].getLocation()!=null?mList[x].getLocation().getName():"No Location Set";
					mobPanel.addRow(
						new JLabel(mList[x].getName()),
						new JLabel(mList[x].getDescription()),
						new JLabel(location),
						new JLabel(String.valueOf(mList[x].getBovineList().length)));
					final long id = mList[x].getID();
					mobPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							edit=false;
							createMobPanel(id);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				groupPanel.setHeaderClickable(DESCRIPTION, false);
				groupPanel.setHeaderOrderedBy(orderGroupListBy==LIST_ORDER_NAME?NAME:orderGroupListBy==LIST_ORDER_COUNT?GROUP_COUNT:NAME, orderGroupHighToLow==1);
				groupPanel.addHeaderMouseListener(NAME, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderGroupHighToLow = orderGroupHighToLow*(orderGroupListBy==LIST_ORDER_NAME?-1:1);
						orderGroupListBy = LIST_ORDER_NAME;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				groupPanel.addHeaderMouseListener(GROUP_COUNT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderGroupHighToLow = orderGroupHighToLow*(orderGroupListBy==LIST_ORDER_COUNT?-1:1);
						orderGroupListBy = LIST_ORDER_COUNT;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Group[] gList = LivestockSolutions.getOnlyGroups();
				Arrays.sort(gList, 
					orderGroupListBy==LIST_ORDER_NAME?
						orderGroupHighToLow==1?Comparators.groupComparatorName:Collections.reverseOrder(Comparators.groupComparatorName)
					:orderGroupHighToLow==1?Comparators.groupComparatorCount:Collections.reverseOrder(Comparators.groupComparatorCount));

				for(int x=0; x<gList.length; x++){
					groupPanel.addRow(
						new JLabel(gList[x].getName()),
						new JLabel(gList[x].getDescription()),
						new JLabel(String.valueOf(gList[x].getBovineList().length)));
					final long id = gList[x].getID();
					groupPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							edit=false;
							createGroupPanel(id);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		panel.removeAll();
		JPanel container1 = new JPanel();
		container1.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel1 = new JPanel();
		((FlowLayout)buttonPanel1.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewMob = new JButton("New Mob");
		btnNewMob.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createMobPanel(-1L);
			}
		});
		buttonPanel1.add(btnNewMob);
		container1.add(buttonPanel1,BorderLayout.NORTH);
		container1.add(mobPanel,BorderLayout.CENTER);
		panel.add(container1,BorderLayout.NORTH);
		
		JPanel container2 = new JPanel();
		container2.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel2 = new JPanel();
		((FlowLayout)buttonPanel2.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewGroup = new JButton("New Group");
		btnNewGroup.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createGroupPanel(-1L);
			}
		});
		buttonPanel2.add(btnNewGroup);
		container2.add(buttonPanel2,BorderLayout.NORTH);
		container2.add(groupPanel,BorderLayout.CENTER);
		panel.add(container2,BorderLayout.CENTER);
	}
	
	/**
	 * Create and display buttons relating to Modification, Viewing and adding of a Group/Mob or any of
	 * its attributes.
	 */
	protected synchronized void setGroupMobViewButton(){
		/**
		 * The Group or Mob that is being shown.
		 */
		final long groupViewID = this.groupViewID;
		JButton btnHome = new JButton("Mobs and Groups List");
		btnHome.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				txtName.setText("-1");
				viewing=-1;
				displayPanel(MOB_GROUP_LIST);
			}
		});
		
		JPanel buttonMenuLeft = new JPanel();
		JPanel buttonMenuRight = new JPanel();
		((FlowLayout)buttonMenuLeft.getLayout()).setAlignment(FlowLayout.LEFT);
		((FlowLayout)buttonMenuRight.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		if(groupViewID==-1 || LivestockSolutions.getGroupByID(groupViewID)!=null){
			JButton btnCancel = new JButton(groupViewID!=-1?"Cancel":"Clear");
			btnCancel.setVisible(edit);
			btnCancel.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					edit=false;
					txtName.setText("-1");
					bovineAddList.clear();
					displayPanel(viewing);
				}
			});
			
			JButton btnCreateSave = new JButton(groupViewID==-1?"Create":edit?"Save":"Edit");
			btnCreateSave.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(edit){
						Group g = LivestockSolutions.getGroupByID(groupViewID);
						if(viewType==MOB){
							if(groupViewID==-1){
								g = new Mob("");
							}
							((Mob)g).setLocation(listLocation.getSelectedIndex()<=0?null:paddocks[listLocation.getSelectedIndex()-1]);
						}else if(groupViewID==-1){
							g = new Group("");
						}
						g.setName(txtName.getText());
						g.setDescription(txtDescription.getText());
						if(LivestockSolutions.addGroup(g)){
							List<Bovine> memberList = Arrays.asList(g.getBovineList());
							for(Bovine b : bovineAddList){
								if(memberList.contains(b)){
									if(g instanceof Mob){
										b.setMob(null);
									}else{
										b.removeGroup(g);
									}
								}else{
									if(g instanceof Mob){
										b.setMob((Mob)g);
									}else{
										b.addGroup(g);
									}
								}
							}
							bovineAddList.clear();
							GroupPanel.this.groupViewID=g.getID();
							txtName.setText("-1");
							edit=!edit;
						}else{
							JOptionPane.showMessageDialog(MainFrame.getInstance(),"Another Group or Mob has the same name as this, please change the name and try again.","Duplicate Name", JOptionPane.OK_OPTION);
						}
					}else{
						txtName.setText("-1");
						edit=!edit;
						bovineAddList.clear();
					}
					displayPanel(viewing);
				}
			});
			
			final JButton btnMembersInactive = new JButton("Set Members Inactive");
			final JButton btnAddFeed = new JButton("Add Feed to members");
			final JButton btnAddMedicine = new JButton("Add Medicine to members");
			
			btnAddFeed.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					new GroupUsedFeed(LivestockSolutions.getGroupByID(groupViewID),null).addWindowListener(null);
				}
			});
			
			btnAddMedicine.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					new GroupUsedMedicine(LivestockSolutions.getGroupByID(groupViewID),null).addWindowListener(null);				}
			});
			Group g = LivestockSolutions.getGroupByID(groupViewID);
			boolean activeMembers = false;
			if(g!=null){
				for(Bovine b : g.getBovineList()){
					if(b.isActive()){
						activeMembers=true;
					}
				}
			}
			
			btnMembersInactive.setEnabled(activeMembers);
			
			btnMembersInactive.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					final JFrame jf = new JFrame();
					jf.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
					jf.setTitle("Set Active Members to Inactive");
					jf.setLayout(new BorderLayout(0,0));
					
					final JPanel inactivePanel = new JPanel();
					inactivePanel.setBorder(new EmptyBorder(5,5,5,5));
					inactivePanel.setLayout(new BorderLayout(5, 0));
					jf.add(inactivePanel, BorderLayout.NORTH);
					
					JPanel inactiveDatePanel = new JPanel();
					inactivePanel.add(inactiveDatePanel, BorderLayout.WEST);
					inactiveDatePanel.setLayout(new BorderLayout(5, 0));
					
					JLabel lblDeacquire = new JLabel("Date:");
					inactiveDatePanel.add(lblDeacquire, BorderLayout.WEST);
					
					final JComboBox lstDeacquireMethod = new JComboBox();
					final JDatePickerDate txtDeacquireDate = JDatePickerDate.createJDatePicker();
					final JSpinner sellPrice = new JSpinner();
					final JComboBox lstNewOwner = new JComboBox();
					
					lstDeacquireMethod.setModel(new DefaultComboBoxModel(new String[] {"Death", "Sold"}));
					sellPrice.setModel(new SpinnerNumberModel(new Double(0.00), new Double(0.00), null, new Double(1.00)));

					
					txtDeacquireDate.setDate(new Date());
					txtDeacquireDate.setEnabled(true);
					
					inactiveDatePanel.add(txtDeacquireDate, BorderLayout.CENTER);
					
					JPanel inactiveMethodPanel = new JPanel();
					inactivePanel.add(inactiveMethodPanel, BorderLayout.CENTER);
					inactiveMethodPanel.setLayout(new BorderLayout(5, 0));
					
					JLabel lblDeacquireBy = new JLabel("Inactive By:");
					inactiveMethodPanel.add(lblDeacquireBy, BorderLayout.WEST);
					
					JPanel inactiveMethodValuePanel = new JPanel();
					inactiveMethodPanel.add(inactiveMethodValuePanel);
					inactiveMethodValuePanel.setLayout(new BorderLayout(0, 0));
		
					final JPanel inactiveSoldPanel = new JPanel();
					
					inactiveMethodValuePanel.add(lstDeacquireMethod, BorderLayout.CENTER);
					lstDeacquireMethod.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent e) {
							inactiveSoldPanel.setVisible(lstDeacquireMethod.getSelectedItem().equals("Sold"));
							sellPrice.setEnabled(true);
						}
					});
					
					inactivePanel.add(inactiveSoldPanel, BorderLayout.SOUTH);
					inactiveSoldPanel.setLayout(new BoxLayout(inactiveSoldPanel,BoxLayout.X_AXIS));

					JPanel inactivePricePanel = new JPanel();
					inactiveSoldPanel.add(inactivePricePanel);
					inactivePricePanel.setBorder(new EmptyBorder(0,0,0,10));
					inactivePricePanel.setLayout(new BoxLayout(inactivePricePanel, BoxLayout.X_AXIS));

					inactivePricePanel.add(new JLabel("Price: $"));
					
					sellPrice.setEnabled(true);
					((JSpinner.DefaultEditor)sellPrice.getEditor()).getTextField().setColumns(10);
					inactivePricePanel.add(sellPrice);
					sellPrice.setValue(0.00);
					
					JPanel inactiveOwnerPanel = new JPanel();
					inactiveSoldPanel.add(inactiveOwnerPanel);
					inactiveOwnerPanel.setLayout(new BorderLayout(0, 0));
					
					JLabel lblNewOwner = new JLabel("Sold to:");
					lblNewOwner.setHorizontalAlignment(SwingConstants.RIGHT);
					inactiveOwnerPanel.add(lblNewOwner,BorderLayout.WEST);
					
					lstNewOwner.setEditable(true);
					inactiveOwnerPanel.add(lstNewOwner,BorderLayout.CENTER);

					JButton btnCreateOrUpdate;
					JButton btnClear;
					JSeparator separator;
					
					JPanel southPanel = new JPanel();
					southPanel.setBorder(new EmptyBorder(0,5,0,5));
					jf.add(southPanel, BorderLayout.SOUTH);
					southPanel.setLayout(new BorderLayout(0, 5));
					
					separator = new JSeparator();
					southPanel.add(separator, BorderLayout.NORTH);
					btnCreateOrUpdate = new JButton("Save");
					
					Owner[] owners = LivestockSolutions.getOwners();
					String[] strOwnerList = new String[owners.length];
					for(int x=0; x<owners.length; x++){
						strOwnerList[x]=owners[x].getName();
					}
					
					lstNewOwner.setModel(new DefaultComboBoxModel(strOwnerList));
					
					final Group g = LivestockSolutions.getGroupByID(groupViewID);
					
					btnCreateOrUpdate.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							Date date = txtDeacquireDate.getDate();
							if(date==null){
								JOptionPane.showMessageDialog(jf,"A date must be set.","Can not save", JOptionPane.OK_OPTION);
								return;
							}
							
							for(Bovine b : g.getBovineList()){
								if(b.getAcquisition().getDate().after(date)){
									JOptionPane.showMessageDialog(jf,"The date given ("+txtDeacquireDate.getText()+") is set before the animal with the visual ID: \""+b.getEartag().getEartagID()+"\" was acquired.","Invalid Date", JOptionPane.OK_OPTION);
									return;
								}
							}
							
							Owner po = null;
							float price = 0f;
							String method = (String)lstDeacquireMethod.getSelectedItem();
							if(!method.trim().toLowerCase().equals("death")){
								po = new Owner();
								po.setName((String)lstNewOwner.getSelectedItem());
								for(Owner o : LivestockSolutions.getOwners()){
									po = o.getName().toLowerCase().equals(((String)lstNewOwner.getSelectedItem()).trim().toLowerCase())?o:po;
								}
								price = ((Double)sellPrice.getValue()).floatValue();
								LivestockSolutions.addOwner(po);
							}
							
							int count = 0;
							for(Bovine b : g.getBovineList()){
								if(b.isActive()){
									count++;
									b.setDeacquisition(new Deacquisition(method,price,po,date));
								}
							}
							
							JOptionPane.showMessageDialog(jf,count+" Group member"+(count!=1?"s":"")+" marked as inactive ("+method+")","Members marked as inactive", JOptionPane.OK_OPTION);
							jf.dispose();
							displayPanel();
						}
					});
					
					JPanel buttonPanel = new JPanel();
					add(buttonPanel, BorderLayout.SOUTH);
					FlowLayout flowLayout = (FlowLayout) buttonPanel.getLayout();
					flowLayout.setAlignment(FlowLayout.RIGHT);
					
					btnClear = new JButton("Clear");
					btnClear.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							lstDeacquireMethod.setSelectedIndex(0);
							txtDeacquireDate.setDate(new Date());
							sellPrice.setValue(0.00);
							lstNewOwner.setSelectedIndex(lstNewOwner.getItemCount()>0?0:-1);
						}
					});
					buttonPanel.add(btnClear);
					buttonPanel.add(btnCreateOrUpdate);
					southPanel.add(buttonPanel, BorderLayout.CENTER);
					jf.pack();
					
					inactiveSoldPanel.setVisible(lstDeacquireMethod.getSelectedItem().equals("Sold"));
					sellPrice.setEnabled(true);
					
					jf.setAlwaysOnTop(true);
					jf.setLocationRelativeTo(MainFrame.getInstance());
					jf.setVisible(true);
				}
			});
			
			if(groupViewID!=-1){
				buttonMenuRight.add(btnMembersInactive);
				buttonMenuRight.add(btnAddMedicine);
				buttonMenuRight.add(btnAddFeed);
				buttonMenuRight.add(new JSeparator());
			}
			
			buttonMenuRight.add(btnCreateSave);
			buttonMenuRight.add(btnCancel);
		}
		
		buttonMenuLeft.add(btnHome);
		JPanel buttonMenu = new JPanel();
		buttonMenu.setLayout(new BorderLayout());
		buttonMenu.add(buttonMenuLeft,BorderLayout.WEST);
		buttonMenu.add(buttonMenuRight,BorderLayout.EAST);
		((JPanel)panel.getComponent(0)).add(buttonMenu,BorderLayout.NORTH);
	}
	
	/**
	 * Create the elements to display details of the mob with the given ID.
	 * @param mobID The id of the mob to show details for, if the value is -1,
	 * then this will create a new mob.
	 * @return <tt>true</tt> if the Mob at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createMobPanel(final long mobID){
		if(groupViewID != mobID){
			viewing=MOB;
			groupViewID = mobID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			edit=false;
			txtName.setText("-1");
		}
		viewType=MOB;
		
		panel.setLayout(new BorderLayout(10, 10));
		panel.removeAll();

		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		JPanel flowPanel = new JPanel();
		JPanel panel_1 = new JPanel();
		panel_1.setLayout(new BorderLayout(0, 10));
		flowPanel.add(panel_1);
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);

		final Mob mob = (Mob)LivestockSolutions.getGroupByID(mobID);
		if(mob!=null || mobID==-1){
			String name = "";
			String description = "";
			long locationID = 0L;
			int selected=0;
			
			if(mob!=null){
				name = mob.getName();
				description = mob.getDescription();
				if(mob.getLocation()!=null){
					locationID = mob.getLocation().getID();
				}
			}else{
				if(mobID==-1){
					edit=true;
				}
			}
			ArrayList<Paddock> pTList = new ArrayList<Paddock>(Arrays.asList(LivestockSolutions.getOnlyPaddocks()));
			ArrayList<String> pTNames = new ArrayList<String>();
			pTNames.add("None");
			Iterator<Paddock> i = pTList.iterator();
			while(i.hasNext()){
				Paddock p =i.next();
				if(p.isSafeToUse()){
					pTNames.add(p.getName());
					if(p.getID()==locationID){
						selected=pTList.indexOf(p)+1;
					}
				}else{
					i.remove();
				}
			}
			paddockNames = pTNames.toArray(new String[]{});
			paddocks = pTList.toArray(new Paddock[]{});
			if(jisp.indexOfComponent(observationsListPanel)==-1){
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Observations",MainFrame.scale(MainFrame.getImageIcon(MainFrame.OBSERVATION_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), observationsListPanel);
				jisp.addTab("Members",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CATTLE_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), membersListPanel);
				jisp.addTab("Joinings",MainFrame.scale(MainFrame.getImageIcon(MainFrame.JOINING_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), joiningListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==observationsListPanel)
								createObservationsPanel(mobID);
							else if(jisp.getSelectedComponent()==membersListPanel)
								createMembersPanel(mobID);
							else if(jisp.getSelectedComponent()==joiningListPanel)
								createJoiningsPanel(mobID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}
			
			JPanel containerPanel = new JPanel();
			containerPanel.setLayout(new BorderLayout(0, 0));
			
			JPanel topPanel = new JPanel();
			topPanel.setLayout(new BoxLayout(topPanel,BoxLayout.LINE_AXIS));
			
			JPanel namePanel = new JPanel();
			namePanel.setLayout(new BoxLayout(namePanel,BoxLayout.PAGE_AXIS));
			JPanel valuePanel = new JPanel();
			valuePanel.setLayout(new BoxLayout(valuePanel,BoxLayout.PAGE_AXIS));
			
			topPanel.add(namePanel);
			topPanel.add(valuePanel);
			
			JPanel groupNamePanel = new JPanel();
			namePanel.add(groupNamePanel);
			groupNamePanel.setLayout(new BorderLayout(0, 0));
			
			JPanel groupLocationPanel = new JPanel();
			namePanel.add(groupLocationPanel);
			groupLocationPanel.setLayout(new BorderLayout(0, 0));
			
			groupNamePanel.add(new JLabel("Mob Name:"));
			groupLocationPanel.add(new JLabel("Location:"));
			
			valuePanel.add(txtName);
			
			JPanel listPadPanel = new JPanel();
			valuePanel.add(listPadPanel);
			
			JPanel descrPanel = new JPanel();
			descrPanel.setLayout(new BorderLayout(5,5));
			descrPanel.add(new JLabel("Description:"),BorderLayout.NORTH);
			descrPanel.add(txtDescription,BorderLayout.CENTER);
			
			JPanel content = new JPanel();
			content.setLayout(new BorderLayout(5,5));
			JPanel elements = new JPanel();
			elements.add(topPanel,BorderLayout.NORTH);
			content.add(elements, BorderLayout.NORTH);
			content.add(descrPanel, BorderLayout.CENTER);
			containerPanel.add(content, BorderLayout.NORTH);
			
			
			boolean refresh=false;
			if(!txtName.getText().equals("-1")){
				refresh=true;
			}
			txtName.setText(refresh?txtName.getText():name);
			txtName.setEditable(edit);
			txtName.setColumns(5);

			if(!refresh){
				listLocation.setModel(new DefaultComboBoxModel(paddockNames));
				listLocation.setEnabled(edit);
				listLocation.setSelectedIndex(selected);
			}
			FlowLayout flowLayout = (FlowLayout) listPadPanel.getLayout();
			flowLayout.setAlignment(FlowLayout.LEFT);
			listPadPanel.add(listLocation);
			
			if(mob!=null&&mob.getLocation()!=null&&!edit){
				JButton paddockView = new JButton("View");
				paddockView.addActionListener(new ActionListener(){
					@Override
					public void actionPerformed(ActionEvent arg0) {
						if(!MainFrame.getInstance().showPaddock(mob.getLocation().getID())){
							// Show paddock not found message?
						}
					}
				});
				listPadPanel.add(paddockView);//,BorderLayout.EAST);
			}
			
			txtDescription.setText(refresh?txtDescription.getText():description);
			txtDescription.setEditable(edit);
			txtDescription.setRows(3);
			
			containerPanel.add(jisp, BorderLayout.CENTER);
			
			panel.add(containerPanel, BorderLayout.CENTER);
			
			if(viewing == VIEW_MEMBER){
				jisp.setSelectedComponent(membersListPanel);
				createMembersPanel(mobID);
			}else if(viewing == MOB_JOINING){
				jisp.setSelectedComponent(joiningListPanel);
				createJoiningsPanel(mobID);
			}else{
				jisp.setSelectedComponent(observationsListPanel);
				createObservationsPanel(mobID);
			}
		}else{
			
			panel.removeAll();
			panel.setLayout(new BorderLayout(0, 0));

			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Mob can be found with the given internal id: "+mobID);
			flow.add(label);
			panel.add(flow, BorderLayout.NORTH);
			return false;
		}
		setGroupMobViewButton();
		validate();
		return true;
	}
	
	/**
	 * Create the elements to display details of the Group with the given ID.
	 * @param groupID The id of the group to show details for, if the value is -1,
	 * then this will create a new group.
	 * @param bovines The Bovines to add selected to the Group.
	 * @return <tt>true</tt> if the Group at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createGroupPanel(long groupID, Bovine...bovines){
		boolean value = createGroupPanel(groupID);
		edit=true;
		viewing=VIEW_MEMBER;
		bovineAddList.clear();
		for(Bovine b : bovines){
			bovineAddList.add(b);
		}
		setGroupMobViewButton();
		return value;
	}
	
	/**
	 * Create the elements to display details of the Group with the given ID.
	 * @param groupID The id of the group to show details for, if the value is -1,
	 * then this will create a new group.
	 * @return <tt>true</tt> if the Group at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createGroupPanel(final long groupID){
		if(groupViewID != groupID){
			viewing=GROUP;
			groupViewID = groupID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			edit=false;
			txtName.setText("-1");
		}
		viewType=GROUP;
		
		panel.setLayout(new BorderLayout(10, 10));
		panel.removeAll();

		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		JPanel flowPanel = new JPanel();
		JPanel panel_1 = new JPanel();
		panel_1.setLayout(new BorderLayout(0, 10));
		flowPanel.add(panel_1);
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		
		final Group group = LivestockSolutions.getGroupByID(groupID);
		if(group!=null || groupID==-1){
			if(group instanceof Mob){
				return createMobPanel(groupID);
			}
			String name = "";
			String description = "";
			
			if(group!=null){
				name = group.getName();
				description = group.getDescription();
			}else{
				if(groupID==-1){
					edit=true;
				}
			}
			
			if(jisp.indexOfComponent(observationsListPanel)==-1){
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Observations",MainFrame.scale(MainFrame.getImageIcon(MainFrame.OBSERVATION_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), observationsListPanel);
				jisp.addTab("Members",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CATTLE_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), membersListPanel);
				jisp.addTab("Joinings",MainFrame.scale(MainFrame.getImageIcon(MainFrame.JOINING_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), joiningListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==observationsListPanel)
								createObservationsPanel(groupID);
							else if(jisp.getSelectedComponent()==membersListPanel)
								createMembersPanel(groupID);
							else if(jisp.getSelectedComponent()==joiningListPanel)
								createJoiningsPanel(groupID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}
			
			JPanel containerPanel = new JPanel();
			containerPanel.setLayout(new BorderLayout(0, 0));
			
			JPanel topPanel = new JPanel();
			topPanel.setLayout(new BoxLayout(topPanel,BoxLayout.LINE_AXIS));
			
			JPanel namePanel = new JPanel();
			namePanel.setLayout(new BoxLayout(namePanel,BoxLayout.PAGE_AXIS));
			JPanel valuePanel = new JPanel();
			valuePanel.setLayout(new BoxLayout(valuePanel,BoxLayout.PAGE_AXIS));
			
			topPanel.add(namePanel);
			topPanel.add(valuePanel);
			
			JPanel groupNamePanel = new JPanel();
			namePanel.add(groupNamePanel);
			groupNamePanel.setLayout(new BorderLayout(0, 0));
			
			groupNamePanel.add(new JLabel("Group Name:"));
			
			valuePanel.add(txtName);
			
			JPanel descrPanel = new JPanel();
			descrPanel.setLayout(new BorderLayout(5,5));
			descrPanel.add(new JLabel("Description:"),BorderLayout.NORTH);
			descrPanel.add(txtDescription,BorderLayout.CENTER);
			
			JPanel content = new JPanel();
			content.setLayout(new BorderLayout(5,5));
			JPanel elements = new JPanel();
			elements.add(topPanel,BorderLayout.NORTH);
			content.add(elements, BorderLayout.NORTH);
			content.add(descrPanel, BorderLayout.CENTER);
			containerPanel.add(content, BorderLayout.NORTH);
			
			boolean refresh=false;
			if(!txtName.getText().equals("-1")){
				refresh=true;
			}
			txtName.setText(refresh?txtName.getText():name);
			txtName.setEditable(edit);
			txtName.setColumns(20);
			
			txtDescription.setText(refresh?txtDescription.getText():description);
			
			containerPanel.add(jisp,BorderLayout.CENTER);
			panel.add(containerPanel, BorderLayout.CENTER);
			
			if(viewing == VIEW_MEMBER){
				jisp.setSelectedComponent(membersListPanel);
				createMembersPanel(groupID);
			}else{
				jisp.setSelectedComponent(observationsListPanel);
				createObservationsPanel(groupID);
			}
			
		}else{
			
			panel.removeAll();
			panel.setLayout(new BorderLayout(0, 0));

			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Group can be found with the given internal id: "+groupID);
			flow.add(label);
			panel.add(flow, BorderLayout.NORTH);
			return false;
		}
		setGroupMobViewButton();
		return true;
	}

	/**
	 * Create a list of observations that belong to this Group or Mob
	 * @param groupID The long ID value that represents the Group or Mob to show the Observations for.
	 */
	private void createObservationsPanel(final long groupID){
		viewing = VIEW_OBSERVATION;
		observationsListPanel.setLayout(new BorderLayout(0, 0));
		
		final int DATE 		= 0;
		final int DESCRIPTION 	= 1;
		final int PRIORITY 	= 2;
		
		final Table observationPanel = new Table("Observations",false,
			"Date","Description","Priority");
		observationPanel.setEmptyMessage("There are no observations to show.");
		
		new Thread(){
			@Override
			public void run(){
				observationPanel.setHeaderClickable(DESCRIPTION, false);
				observationPanel.setHeaderOrderedBy(orderObservationListBy==LIST_ORDER_DATE?DATE:orderObservationListBy==LIST_ORDER_PRIORITY?PRIORITY:DATE, orderObservationHighToLow==1);
				observationPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_DATE?-1:1);
						orderObservationListBy = LIST_ORDER_DATE;
						createObservationsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				observationPanel.addHeaderMouseListener(PRIORITY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_PRIORITY?-1:1);
						orderObservationListBy = LIST_ORDER_PRIORITY;
						createObservationsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				final Group g = LivestockSolutions.getGroupByID(groupID);
				Observation[] oList = g!=null?g.getObservations():new Observation[]{};
		
				Arrays.sort(oList, 
					orderObservationListBy==LIST_ORDER_DATE?
							orderObservationHighToLow==1?Comparators.observationComparatorDate:Collections.reverseOrder(Comparators.observationComparatorDate)
					:orderObservationHighToLow==1?Comparators.observationComparatorPriority:Collections.reverseOrder(Comparators.observationComparatorPriority));

				for(int x=0; x<oList.length; x++){
					observationPanel.addRow(
						new JLabel(JDatePickerDate.format(oList[x].getDate())),
						new JLabel(oList[x].getComment()),
						new JLabel(Observation.getPriorityString(oList[x].getPriority())));
					
					final Observation o = oList[x];
					
					observationPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new ObservationFrame(g,o,(g instanceof Mob?"Mob":"Group")+": "+g.getName()).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_OBSERVATION && groupViewID==groupID){
										createObservationsPanel(groupID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();

		final JButton btnAddObservation = new JButton("Add Observation");
		btnAddObservation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Group g = LivestockSolutions.getGroupByID(groupViewID);
				new ObservationFrame(g,null,(g instanceof Mob?"Mob":"Group")+": "+g.getName()).addWindowListener(new WindowListener(){
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_OBSERVATION && GroupPanel.this.groupViewID==groupViewID){
							createObservationsPanel(groupViewID);
						}
					}
					@Override public void windowOpened(WindowEvent e) {}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
				observationPanel.addRow(null,new JLabel("<New Observation>"),null);
				btnAddObservation.setEnabled(false);
				observationPanel.validate();
				panel.validate();
			}
		});
		
		observationsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddObservation);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(observationPanel,BorderLayout.CENTER);
		observationsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
	}
	
	/**
	 * Create a list of members that belong to this Group or Mob
	 * @param groupID The long ID value that represents the Group or Mob to show the Members for.
	 */
	private void createMembersPanel(final long groupID){
		viewing = VIEW_MEMBER;
		
		membersListPanel.setLayout(new BorderLayout(0, 0));
		final JPanel memberAddListPanel = new JPanel();
		memberAddListPanel.setLayout(new BorderLayout(0, 0));
		
		final int ADD		= 0;
		final int VISUAL	= 1;
		final int NLIS		= 2;
		final int RF		= 3;
		final int DOB 		= 4;
		final int ACTIVE	= 5;
		
		final Group g = LivestockSolutions.getGroupByID(groupID);
		
		final Table bovinePanel = new Table("Members",false,
			"Include as Member","Visual ID","NLIS","RF ID","DOB","Status");
		bovinePanel.setEmptyMessage("There are no cattle in this "+(g instanceof Mob?"Mob":"Group")+".");
		
		final Table bovineAddPanel = new Table("Offspring",false,
				"Add to "+(g instanceof Mob?"Mob":"Group"),"Visual ID","NLIS","RF ID","DOB","Status");
			bovineAddPanel.setEmptyMessage("There are no more cattle to add to this "+(g instanceof Mob?"Mob":"Group")+".");
			
		new Thread(){
			@Override
			public void run(){
				bovinePanel.setHeaderOrderedBy(orderMemberListBy==LIST_ORDER_VISUAL?VISUAL:orderMemberListBy==LIST_ORDER_RF?RF:orderMemberListBy==LIST_ORDER_NLIS?NLIS:orderMemberListBy==LIST_ORDER_DOB?DOB:orderMemberListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderMemberHighToLow==1);
				bovinePanel.setHeaderClickable(ADD, false);
				bovinePanel.addHeaderMouseListener(VISUAL, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_VISUAL?-1:1);
						orderMemberListBy = LIST_ORDER_VISUAL;
						createMembersPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(RF, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_RF?-1:1);
						orderMemberListBy = LIST_ORDER_RF;
						createMembersPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(NLIS, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_NLIS?-1:1);
						orderMemberListBy = LIST_ORDER_NLIS;
						createMembersPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(DOB, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_DOB?-1:1);
						orderMemberListBy = LIST_ORDER_DOB;
						createMembersPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(ACTIVE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_ACTIVE?-1:1);
						orderMemberListBy = LIST_ORDER_ACTIVE;
						createMembersPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Bovine[] bList = g!=null?g.getBovineList():new Bovine[]{};
				
				Arrays.sort(bList, 
					orderMemberListBy==LIST_ORDER_VISUAL?
						orderMemberHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
					:orderMemberListBy==LIST_ORDER_NLIS?
						orderMemberHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
					:orderMemberListBy==LIST_ORDER_RF?
						orderMemberHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
					:orderMemberListBy==LIST_ORDER_DOB?
						orderMemberHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
					:orderMemberHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));

				for(int x=0; x<bList.length; x++){
					final JCheckBox add = new JCheckBox();
					// Set this Animal to selected if it is currently selected.
					add.setSelected(!bovineAddList.contains(bList[x]));
					add.setEnabled(edit);
					bovinePanel.addRow(
						add,
						new JLabel(bList[x].getEartag().getEartagID()),
						new JLabel(bList[x].getEartag().getNlisID()),
						new JLabel(bList[x].getEartag().getRfID()),
						new JLabel(bList[x].getDob()!=null?JDatePickerDate.format(bList[x].getDob()):"Unknown"),
						new JLabel(bList[x].isActive()?"Active":bList[x].getDeacquisition().getMethod()));

					final Bovine b = bList[x];
					bovinePanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!edit) {
								if(!MainFrame.getInstance().showBovine(b.getID())) {
									// Show not found message?
								}
							}else{
								add.setSelected(!add.isSelected());
								if(add.isSelected()){
									bovineAddList.remove(b);
								}else{
									bovineAddList.add(b);
								}
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					
					bovinePanel.addDefaultMouseListenerTo(add);
					add.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!edit) {
								if(!MainFrame.getInstance().showBovine(b.getID())) {
									// Show not found message?
								}
							}else{
								if(add.isSelected()){
									bovineAddList.remove(b);
								}else{
									bovineAddList.add(b);
								}
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				
				if(g!=null&&edit){
					bovineAddPanel.setHeaderOrderedBy(orderMemberListBy==LIST_ORDER_VISUAL?VISUAL:orderMemberListBy==LIST_ORDER_RF?RF:orderMemberListBy==LIST_ORDER_NLIS?NLIS:orderMemberListBy==LIST_ORDER_DOB?DOB:orderMemberListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderMemberHighToLow==1);
					bovineAddPanel.setHeaderClickable(ADD, false);
					bovineAddPanel.addHeaderMouseListener(VISUAL, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_VISUAL?-1:1);
							orderMemberListBy = LIST_ORDER_VISUAL;
							createMembersPanel(groupID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(RF, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_RF?-1:1);
							orderMemberListBy = LIST_ORDER_RF;
							createMembersPanel(groupID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(NLIS, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_NLIS?-1:1);
							orderMemberListBy = LIST_ORDER_NLIS;
							createMembersPanel(groupID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(DOB, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_DOB?-1:1);
							orderMemberListBy = LIST_ORDER_DOB;
							createMembersPanel(groupID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(ACTIVE, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_ACTIVE?-1:1);
							orderMemberListBy = LIST_ORDER_ACTIVE;
							createMembersPanel(groupID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					
					Bovine[] allbalist = LivestockSolutions.getBovines(); // Get all Bovines
					ArrayList<Bovine> balist = g!=null?new ArrayList<Bovine>(Arrays.asList(g.getBovineList())):new ArrayList<Bovine>(); // Use a list of no filters.
					Arrays.sort(allbalist, 
						orderMemberListBy==LIST_ORDER_VISUAL?
							orderMemberHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
						:orderMemberListBy==LIST_ORDER_NLIS?
							orderMemberHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
						:orderMemberListBy==LIST_ORDER_RF?
							orderMemberHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
						:orderMemberListBy==LIST_ORDER_DOB?
							orderMemberHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
						:orderMemberHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));

					ArrayList<Bovine> barrList = new ArrayList<Bovine>(Arrays.asList(allbalist));
					Iterator<Bovine> i = barrList.iterator();
					while(i.hasNext()){
						Bovine b = i.next();
						if(balist.contains(b) || !b.isActive()){
							i.remove();
						}
					}
					
					for(int x=0; x<barrList.size(); x++){
						final JCheckBox add = new JCheckBox();
						// Set this Animal to selected if it is in the Group filter list.
						add.setSelected(bovineAddList.contains(barrList.get(x)));
						
						bovineAddPanel.addRow(
							add,
							new JLabel(barrList.get(x).getEartag().getEartagID()),
							new JLabel(barrList.get(x).getEartag().getNlisID()),
							new JLabel(barrList.get(x).getEartag().getRfID()),
							new JLabel(barrList.get(x).getDob()!=null?JDatePickerDate.format(barrList.get(x).getDob()):"Unknown"),
							new JLabel(barrList.get(x).isActive()?"Active":barrList.get(x).getDeacquisition().getMethod()));

						final Bovine b = barrList.get(x);
						bovineAddPanel.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								add.setSelected(!add.isSelected());
								if(add.isSelected()){
									bovineAddList.add(b);
								}else{
									bovineAddList.remove(b);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
						
						bovineAddPanel.addDefaultMouseListenerTo(add);
						add.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								if(add.isSelected()){
									bovineAddList.add(b);
								}else{
									bovineAddList.remove(b);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
					}
					
					JPanel flow =new JPanel();
					JLabel label = new JLabel("Select any of the following cattle to add to this "+(g instanceof Mob?"Mob":"Group")+".");
					flow.add(label);
					memberAddListPanel.add(flow, BorderLayout.NORTH);
					memberAddListPanel.add(bovineAddPanel, BorderLayout.CENTER);
				}
				validate();
			}
		}.start();
		
		final JButton btnAddMember = new JButton("Add Member");
		btnAddMember.setEnabled(!edit&&g!=null);
		btnAddMember.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=true;
				createGroupPanel(groupID);
			}
		});
		
		membersListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddMember);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(bovinePanel,BorderLayout.CENTER);
		container.add(memberAddListPanel, BorderLayout.SOUTH);
		membersListPanel.add(container, BorderLayout.NORTH);
	}
	
	/**
	 * Create a list of joinings that belong to this Mob
	 * @param groupID The long ID value that represents the Mob to show the Members for.
	 */
	private void createJoiningsPanel(final long groupID){
		viewing = MOB_JOINING;
		joiningListPanel.setLayout(new BorderLayout(0, 0));
		
		final int BULL_IN 	= 0;
		final int BULL_OUT	= 1;
		final int BULL 	= 2;
		final int COUNT	= 3;
		
		final Table joiningPanel = new Table("Joinings",false,
			"Bull Entry Date","Butt Exit Date","Bull Visual ID","No. Members");
		joiningPanel.setEmptyMessage("There are no Joinings to show.");
		
		
		new Thread(){
			@Override
			public void run(){
				joiningPanel.setHeaderOrderedBy(orderJoiningListBy==LIST_ORDER_ENTRY?BULL_IN:orderJoiningListBy==LIST_ORDER_EXIT?BULL_OUT:orderJoiningListBy==LIST_ORDER_BULL?BULL:orderJoiningListBy==LIST_ORDER_COW_COUNT?COUNT:BULL_IN, orderJoiningHighToLow==1);
				joiningPanel.addHeaderMouseListener(BULL_IN, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_ENTRY?-1:1);
						orderJoiningListBy = LIST_ORDER_ENTRY;
						createJoiningsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(BULL_OUT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_EXIT?-1:1);
						orderJoiningListBy = LIST_ORDER_EXIT;
						createJoiningsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(BULL, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_BULL?-1:1);
						orderJoiningListBy = LIST_ORDER_BULL;
						createJoiningsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(COUNT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_COW_COUNT?-1:1);
						orderJoiningListBy = LIST_ORDER_COW_COUNT;
						createJoiningsPanel(groupID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Group g = LivestockSolutions.getGroupByID(groupID);
				Join[] jList = g!=null?g.getCurrentJoinings():new Join[]{};
				
				Arrays.sort(jList, 
					orderJoiningListBy==LIST_ORDER_ENTRY?
						orderJoiningHighToLow==1?Comparators.joiningComparatorEntry:Collections.reverseOrder(Comparators.joiningComparatorEntry)
					:orderJoiningListBy==LIST_ORDER_EXIT?
						orderJoiningHighToLow==1?Comparators.joiningComparatorExit:Collections.reverseOrder(Comparators.joiningComparatorExit)
					:orderJoiningListBy==LIST_ORDER_BULL?
						orderJoiningHighToLow==1?Comparators.joiningComparatorBull:Collections.reverseOrder(Comparators.joiningComparatorBull)
					:orderJoiningHighToLow==1?Comparators.joiningComparatorCowCount:Collections.reverseOrder(Comparators.joiningComparatorCowCount));

				for(int x=0; x<jList.length; x++){
					joiningPanel.addRow(
						new JLabel(JDatePickerDate.format(jList[x].getInsertionDate())),
						new JLabel(jList[x].getRemovalDate()!=null?JDatePickerDate.format(jList[x].getRemovalDate()):"Still Active"),
						new JLabel(jList[x].getBull().getEartag().getEartagID()),
						new JLabel(jList[x].getCows()!=null?String.valueOf(jList[x].getCows().length):"0"));
					
					final long id = jList[x].getID();
					joiningPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(MainFrame.getInstance().showJoining(id)){
								//Show message not found?
							}
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		JButton btnAddJoining = new JButton("Add Joining");
		
		btnAddJoining.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				//TODO maybe allow selection of a new Joining or existing Joining
				if(!MainFrame.getInstance().showJoining(-1,groupViewID)){
					setGroupMobViewButton();
					JOptionPane.showMessageDialog(MainFrame.getInstance(),"There appears to be no eligible Bulls to create a Joining with","Problem creating new Joining", JOptionPane.OK_OPTION);
				}
				createJoiningsPanel(groupViewID);
			}
		});
		
		joiningListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddJoining);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(joiningPanel,BorderLayout.CENTER);
		joiningListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
	}

	/**
	 * Create a window where a Medicine that has been used on the current Group can be viewed and modified.
	 * @author Adam Parr
	 */
	private static class GroupUsedMedicine extends UsedItemFrame<Group,MedicineHistory,Medicine>{
		private static final long serialVersionUID = 1L;
		protected JDatePickerDate expiration;
		protected JDatePickerDate manuDate;
		protected JTextField batchNo;
		
		/**
		 * Constructor.
		 * @param parent The Group in which the usedMedicineHistory has been applied to.
		 * @param usedMedicineHistory the usage history of a particular Medicine, or <tt>null</tt> in the
		 * 			case of a new Medicine usage being used on the Group provided in parent.
		 */
		protected GroupUsedMedicine(Group parent,MedicineHistory usedMedicineHistory) {
			super(parent, usedMedicineHistory);
			if(parent!=null){
				setTitle((usedMedicineHistory==null?"Add a new Medicine":"Modify "+usedMedicineHistory.getItem().getName())+" for use on "+parent.getName());
			}
		}

		@Override
		protected boolean doCheck(boolean isValid) {
			// Additional values for the UsedMedicine are optional.
			return isValid;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected UsableItemList<Medicine>[] getList() {
			Medicine[] mArrayList = LivestockSolutions.getOnlyMedicines();
			int length=mArrayList.length;
			UsableItemList<Medicine>[] chlist = new UsableItemList[length];
			for(int x=0;x<length;x++){
				chlist[x]=new UsableItemList<Medicine>(mArrayList[x]);
			}
			return chlist;
		}
		
		@Override
		protected void createSecondaryValues(final Group parent, final MedicineHistory usedItemHistory){
			super.createSecondaryValues(parent, usedItemHistory);
			int length = cost.getParent().getComponentCount();
			expiration = JDatePickerDate.createJDatePicker();
			expiration.setTextEditable(true);
			batchNo = new JTextField();
			manuDate = JDatePickerDate.createJDatePicker();
			manuDate.setTextEditable(true);
			for(int x=0; x<length; x++){
				Component c = southPanel.getComponent(x);	
				if(c.equals(cost)){
					southPanel.add(expiration,x+1);
					southPanel.add(new JLabel("Expiration Date:"),x+1);
					x+=2;
				}
			}
			southPanel.add(new JLabel("Manufacture Date:"));
			southPanel.add(manuDate);
			southPanel.add(new JLabel("Batch Number:"));
			southPanel.add(batchNo);
			batchNo.setColumns(10);
			pack();
		}
		
		@Override
		protected void setTextInOptionalFields(MedicineHistory usedItemHistory){
			super.setTextInOptionalFields(usedItemHistory);
			if(usedItemHistory!=null){
				expiration.setDate(usedItemHistory.getExpiryDate());
				manuDate.setDate(usedItemHistory.getManufactureDate());
				batchNo.setText(usedItemHistory.getBatchNumber());
			}else{
				expiration.setDate("");
				manuDate.setDate("");
				batchNo.setText("");
			}
		}

		@Override
		protected boolean save(Group parent, MedicineHistory usedItemHistory) {
			MedicineHistory ih = usedItemHistory;
			Medicine i = ((UsableItemList<Medicine>)nameCB.getSelectedItem()).getItem();
			Date d = dateField.getDate();
			double q = Double.parseDouble(quantity.getText());
			String m = (String)measurement.getSelectedItem();
			if(usedItemHistory==null){
				ih = new MedicineHistory(i,q,m,d);
			}else{
				ih.setItem(i);
				ih.setDate(d);
				ih.setQuantity(q,m);
			}

			String co = cost.getText();
			ih.setCost(Double.parseDouble(co.equals("")?"0":co));
			
			if(manuCB.getSelectedItem()!=null&&!((String)manuCB.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)manuCB.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)manuCB.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				ih.setOrigin((Business)po);
			}
			
			ih.setExpiryDate(expiration.getDate());
			ih.setManufactureDate(manuDate.getDate());
			ih.setBatchNumber(batchNo.getText());
			
			if(parent!=null){
				parent.applyMedicineToGroup(ih);
			}
			dispose();
			return true;
		}
	}
	
	/**
	 * Create a window where a Feed that has been given to the current Group can be viewed and modified.
	 * @author Adam Parr
	 */
	private static class GroupUsedFeed extends UsedItemFrame<Group,FeedHistory,Feed>{
		private static final long serialVersionUID = 1L;
		protected JTextField cvd;
		
		/**
		 * Constructor.
		 * @param parent The Group in which the usedFeedHistory has been applied to.
		 * @param usedFeedHistory the usage history of a particular Feed, or <tt>null</tt> in the
		 * 			case of a new Feed usage being given to the Group provided in parent.
		 */
		protected GroupUsedFeed(Group parent,FeedHistory usedFeedHistory) {
			super(parent, usedFeedHistory);
			setTitle((usedFeedHistory==null?"Give a new Feed":"Modify "+usedFeedHistory.getItem().getName()+" that has been given")+" to "+parent.getName());
		}

		@Override
		protected boolean doCheck(boolean isValid) {
			// Additional values for the UsedFeed are optional.
			return isValid;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected UsableItemList<Feed>[] getList() {
			Feed[] mArrayList = LivestockSolutions.getOnlyFeeds();
			int length=mArrayList.length;
			UsableItemList<Feed>[] chlist = new UsableItemList[length];
			for(int x=0;x<length;x++){
				chlist[x]=new UsableItemList<Feed>(mArrayList[x]);
			}
			return chlist;
		}
		
		@Override
		protected void createSecondaryValues(final Group parent, final FeedHistory usedItemHistory){
			super.createSecondaryValues(parent, usedItemHistory);
			cvd=new JTextField();
			southPanel.add(new JLabel("CVD Number:"));
			southPanel.add(cvd);
			cvd.setColumns(10);
			pack();
		}
		
		@Override
		protected void setTextInOptionalFields(FeedHistory usedItemHistory){
			super.setTextInOptionalFields(usedItemHistory);
			if(usedItemHistory!=null){
				cvd.setText(usedItemHistory.getCVDNumber());
			}else{
				cvd.setText("");
			}
		}

		@Override
		protected boolean save(Group parent, FeedHistory usedItemHistory) {
			FeedHistory ih = usedItemHistory;
			Feed i = ((UsableItemList<Feed>)nameCB.getSelectedItem()).getItem();
			Date d = dateField.getDate();
			double q = Double.parseDouble(quantity.getText());
			String m = (String)measurement.getSelectedItem();
			if(usedItemHistory==null){
				ih = new FeedHistory(i,q,m,d);
			}else{
				ih.setItem(i);
				ih.setDate(d);
				ih.setQuantity(q,m);
			}

			String co = cost.getText();
			ih.setCost(Double.parseDouble(co.equals("")?"0":co));
			
			if(manuCB.getSelectedItem()!=null&&!((String)manuCB.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)manuCB.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)manuCB.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				ih.setOrigin((Business)po);
			}
			
			ih.setCVDNumber(cvd.getText());
			
			parent.applyFeedToGroup(ih);
			dispose();
			return true;
		}
	}

	@Override
	public long getID() {
		return groupViewID;
	}
}
